use crate::gen_title;

pub fn ch2_15_1() {
    gen_title("ch2_15_1", 18);

    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            None => None,
            Some(i) => Some(i + 1),
        }
    }

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);

    println!("six: {:?}, none: {:?}", six, none);
}

pub fn ch2_15_2() {
    gen_title("ch2_15_2", 18);
    let mut stack = Vec::new();

    stack.push(1);
    stack.push(2);
    stack.push(3);

    while let Some(top) = stack.pop() {
        println!("{}", top);
    }
}

pub fn ch2_15_3() {
    gen_title("ch2_15_3", 18);

    let v = vec!['a', 'b', 'c'];

    for (index, value) in v.iter().enumerate() {
        println!("{} is at index {}", value, index);
    }
}

pub fn ch2_15_4() {
    gen_title("ch2_15_4", 18);

    fn print_coordinates(&(x, y): &(i32, i32)) {
        println!("x: {}, y: {}", x, y);
    }

    let point = (3, 5);
    print_coordinates(&point);
}

pub fn ch2_15_5() {
    gen_title("ch2_15_5", 18);

    let x = 1;
    match x {
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
}

pub fn ch2_15_6() {
    gen_title("ch2_15_6", 18);

    let x = Some(5);
    let y = 10;

    match x {
        Some(50) => println!("Got 50"),
        Some(y) => println!("Matched, y = {:?}", y),
        _ => println!("Default case, x = {:?}", x),
    }

    println!("at the end: x = {:?}, y = {:?}", x, y);
}

pub fn ch2_15_7() {
    gen_title("ch2_15_7", 18);

    let x = 1;

    match x {
        1 | 2 => println!("one or two"),
        3 => println!("three"),
        _ => println!("others"),
    }
}

pub fn ch2_15_8() {
    gen_title("ch2_15_8", 18);

    let x = 5;
    match x {
        1..=5 => println!("one through five"),
        _ => println!("something else"),
    }

    let x = 'c';

    match x {
        'a'..='j' => println!("early ASCII letter"),
        'k'..='z' => println!("late ASCII letter"),
        _ => println!("something else"),
    }
}

pub fn ch2_15_9() {
    gen_title("ch2_15_9", 18);

    struct Point {
        x: i32,
        y: i32,
    }

    let p = Point { x: 0, y: 7 };

    let Point { x: a, y: b } = p;
    println!("x: {}, y: {}", a, b);

    let Point { x, y } = p;
    println!("x: {}, y: {}", x, y);
}

pub fn ch2_15_10() {
    gen_title("ch2_15_10", 18);

    struct Point {
        x: i32,
        y: i32,
    }

    let p = Point { x: 0, y: 7 };

    match p {
        Point { x, y: 0 } => println!("on the x axis at {}", x),
        Point { x: 0, y } => println!("on the y axis at {}", y),
        Point { x, y } => println!("on neither axis:({},{})", x, y),
    }
}

pub fn ch2_15_11() {
    gen_title("ch2_15_11", 18);

    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }

    let msg = Message::ChangeColor(0, 160, 255);

    match msg {
        Message::Quit => {
            println!("The Quit variant has no data to destructure.");
        }
        Message::Move { x, y } => {
            println!("Move in the x direction {} and in the y direction {}", x, y);
        }
        Message::Write(text) => println!("Text message: {}", text),
        Message::ChangeColor(r, g, b) => {
            println!("Change the color to red {}, green {}, and blue {}", r, g, b)
        }
    }
}

pub fn ch2_15_12() {
    gen_title("ch2_15_12", 18);

    enum Color {
        Rgb(i32, i32, i32),
        Hsv(i32, i32, i32),
    }

    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(Color),
    }

    let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));

    match msg {
        Message::ChangeColor(Color::Rgb(r, g, b)) => {
            println!("Change the color to red {}, green {}, and blue {}", r, g, b)
        }
        Message::ChangeColor(Color::Hsv(h, s, v)) => {
            println!(
                "Change the color to hue {}, saturation {}, and value {}",
                h, s, v
            );
        }
        _ => (),
    }
}

pub fn ch2_15_13() {
    gen_title("ch2_15_13", 18);

    struct Point {
        x: i32,
        y: i32,
    }

    let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });

    println!("feet: {}, inches: {}, x: {}, y: {}", feet, inches, x, y);
}

pub fn ch2_15_14() {
    gen_title("ch2_15_14", 18);

    let arr: [u16; 2] = [113, 514];
    let [x, y] = arr;

    println!("x: {}, y: {}", x, y);

    let arr: &[u16] = &[114, 514];

    if let [x, ..] = arr {
        println!("x: {}", x);
    }

    if let &[.., y] = arr {
        println!("y: {}", y);
    }

    if let &[x, .., y] = arr {
        println!("x: {}, y: {}", x, y);
    }

    let arr: &[u16] = &[1, 2];

    assert!(matches!(arr, [..]));
    assert!(matches!(arr, [x, ..]));
}

pub fn ch2_15_15() {
    gen_title("ch2_15_15", 18);

    fn foo(_: i32, y: i32) {
        println!("This code only uses the y parameter: {}", y);
    }

    foo(3, 4);
}

pub fn ch2_15_16() {
    gen_title("ch2_15_16", 18);

    let mut setting_value = Some(5);
    let new_setting_value = Some(10);

    match (setting_value, new_setting_value) {
        (Some(_), Some(_)) => {
            println!("Can't overwrite an existing customized value");
        }
        _ => {
            setting_value = new_setting_value;
        }
    }

    println!("setting is {:?}", setting_value);
}

pub fn ch2_15_17() {
    gen_title("ch2_15_17", 18);

    let numbers = (2, 4, 8, 16, 32);

    match numbers {
        (first, _, third, _, fifth) => {
            println!("Some numbers:{}, {}, {}", first, third, fifth);
        }
    }
}

pub fn ch2_15_18() {
    gen_title("ch2_15_18", 18);

    let s = Some(String::from("Hello!"));

    if let Some(_) = s {
        println!("found a string");
    }

    println!("{:?}", s);

    if let Some(_s) = s {
        println!("found a string");
        println!("{:?}", _s);
    }
}

pub fn ch2_15_19() {
    gen_title("ch2_15_19", 18);

    struct Point {
        x: i32,
        y: i32,
        z: i32,
    }

    let origin = Point { x: 0, y: 0, z: 0 };

    match origin {
        Point { x, .. } => println!("x is {}", x),
    }
}

pub fn ch2_15_20() {
    gen_title("ch2_15_20", 18);

    let numbers = (2, 4, 8, 16, 32);

    match numbers {
        (first, .., last) => {
            println!("first is {}, last is {}", first, last);
        }
    }
}

pub fn ch2_15_21() {
    gen_title("ch2_15_21", 18);

    let num = Some(4);

    match num {
        Some(x) if x < 5 => println!("less than five: {}", x),
        Some(x) => println!("{}", x),
        None => (),
    }
}

pub fn ch2_15_22() {
    gen_title("ch2_15_22", 18);

    let x = Some(5);
    let y = 10;

    match x {
        Some(50) => println!("Got 50"),
        Some(n) if n == y => println!("Matched, n={}", n),
        _ => println!("Default case, x={:?}", x),
    }

    println!("at the end: x={:?}, y={}", x, y);
}

pub fn ch2_15_23() {
    gen_title("ch2_15_23", 18);

    let x = 4;
    let y = false;

    match x {
        4 | 5 | 6 if y => println!("yes"),
        _ => println!("no"),
    }
}

pub fn ch2_15_24() {
    gen_title("ch2_15_24", 18);

    enum Message {
        Hello { id: i32 },
    }

    let msg = Message::Hello { id: 5 };

    match msg {
        Message::Hello {
            id: id_variable @ 3..=7,
        } => {
            println!("Found an id in range: {}", id_variable);
        }
        Message::Hello { id: 10..=12 } => {
            println!("Found an id in another range");
        }
        Message::Hello { id } => {
            println!("Found some other id: {}", id);
        }
    }
}

pub fn ch2_15_25() {
    gen_title("ch2_15_25", 18);

    #[derive(Debug)]
    struct Point {
        x: i32,
        y: i32,
    }

    let p @ Point { x: px, y: py } = Point { x: 10, y: 32 };
    println!("x: {}, y: {}", px, py);
    println!("p: {:?}", p);

    let point = Point { x: 10, y: 5 };
    if let p @ Point { x: 10, y } = point {
        println!("x is 10 and y is {} in {:?}", y, p);
    } else {
        println!("x was not 10");
    }
}

pub fn ch2_15_26() {
    gen_title("ch2_15_26", 18);

    match 1 {
        num @ (1 | 2) => {
            println!("num is {}", num);
        }
        _ => {}
    }
}

pub fn ch2_15_pra_1() {
    gen_title("ch2_15_pra_1", 18);

    match_number(7);

    fn match_number(n: i32) {
        match n {
            1 => println!("One!"),
            2..=5 => println!("match 2 -> 5"),
            6..=10 => println!("match 6 -> 10"),
            _ => println!("match 11 -> infinite"),
        }
    }
}

pub fn ch2_15_pra_2() {
    gen_title("ch2_15_pra_2", 18);

    struct Point {
        x: i32,
        y: i32,
    }

    let p = Point { x: 3, y: 20 };

    match p {
        Point { x, y: 0 } => println!("On the x axis at {}", x),
        Point {
            x: 0..=5,
            y: y @ (10 | 20 | 30),
        } => println!("One the y axis at {}", y),
        Point { x, y } => println!("On neither axis: ({}, {})", x, y),
    }
}

pub fn ch2_15_pra_3() {
    gen_title("ch2_15_pra_3", 18);

    enum Message {
        Hello { id: i32 },
    }

    let msg = Message::Hello { id: 5 };

    match msg {
        Message::Hello { id: id @ 3..=7 } => println!("id 值的范围在 [3, 7] 之间: {}", id),
        Message::Hello {
            id: new_id @ (10 | 11 | 12),
        } => {
            println!("id 值的范围在 [10, 12] 之间: {}", new_id);
        }
        Message::Hello { id } => println!("id: {}", id),
    }
}

pub fn ch2_15_pra_4() {
    gen_title("ch2_15_pra_4", 18);

    let num = Some(4);
    let split = 5;
    match num {
        Some(x) if x < split => assert!(x < split),
        Some(x) => assert!(x >= split),
        None => (),
    }

    println!("num: {:?}", num);
}

pub fn ch2_15_pra_5() {
    gen_title("ch2_15_pra_5", 18);

    let numbers = (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048);

    match numbers {
        (first, .., last) => {
            assert_eq!(first, 2);
            assert_eq!(last, 2048);
            println!("first: {}, last: {}", first, last);
        }
    }
}

pub fn ch2_15_pra_6() {
    gen_title("ch2_15_pra_6", 18);

    let mut v = String::from("hello, ");
    let mut r = &mut v;

    match &mut r {
        value => value.push_str(" world!"),
    }

    println!("{}", r);
}
